#pragma once

#include<iostream>
#include<string>
#include<vector>
#include<unordered_map>
#include<fstream>
#include"../comm/log.hpp"
#include"../comm/util.hpp"
#include<cassert>
#include<cstdlib>
#include"include/mysql.h"
#include<strings.h>
#include<errno.h>

const std::string oj_questions = "oj_questions";
const std::string host = "localhost";
const std::string user = "oj_client";
const std::string passwd = "QWERTyuiop12345.";
const std::string db = "oj";
const int port = 3306;

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;




    struct User {
        std::string username;
        std::string password;  
        std::string created_at;
    };




    struct Question
    {
        std::string number;
        std::string title; 
        std::string star;  
        std::string desc;  
        std::string header;
        std::string tail;  
        int cpu_limit;     
        int mem_limit;     
    };



    // odel类：所有MySQL操作都在这里
    class Model
    {
    public:
        Model() {}
        ~Model() {}

        // 检查用户是否存在
        bool IsUserExists(const std::string& username) 
        {
            MYSQL* my = mysql_init(nullptr);
            if (!my) 
            {
                LOG(FATAL) << "初始化数据库连接失败";
                return false;
            }
            const char *socket_path = "/var/lib/mysql/mysql.sock";
            if (!mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, socket_path, 0))
            {
                LOG(FATAL) << "连接数据库失败! 错误详情:\n"
                      << "主机: " << host << "\n"
                      << "用户: " << user << "\n"
                      << "数据库: " << db << "\n"
                      << "端口: " << port << "\n"
                      << "MySQL错误: " << mysql_error(my) << "\n"
                      << "系统错误: " << strerror(errno) << "\n";
                mysql_close(my); 
                return false;
            }
            LOG(INFO)<<"连接数据库成功!!!"<<"\n";
            
            mysql_autocommit(my, 1);
            if (mysql_set_character_set(my, "utf8") != 0) 
            {
                LOG(FATAL) << "设置字符集失败";
            }

            char escaped_username[256] = {0};
            mysql_real_escape_string(my, escaped_username, username.c_str(), username.size());

            std::string sql = "SELECT username FROM oj_users WHERE username = '";
            sql += escaped_username;
            sql += "' LIMIT 1";
           
            bool exists = false;
            if (mysql_query(my, sql.c_str()) == 0) 
            {
                // 获取查询结果（mysql_store_result把结果存到内存）
                MYSQL_RES* res = mysql_store_result(my);
                std::cout << "查询结果行数: " << mysql_num_rows(res) << std::endl; 
                if (res && mysql_num_rows(res) > 0) 
                {
                    exists = true;
                }
                if (res) 
                {
                    mysql_free_result(res); // 释放结果集（防止内存泄漏）
                }
            } 
            else 
            {
                LOG(FATAL)<<"查询用户失败"<<"\n";
            }

            mysql_close(my);
            return exists;
        }



        // 注册用户
        bool RegisterUser(const User& user) 
        {
            if (IsUserExists(user.username)) 
            {
                LOG(FATAL)<<"用户已存在"<<"\n";
                return false;
            }

            MYSQL* my = mysql_init(nullptr);
            if (!my) 
            {
                LOG(FATAL) << "初始化数据库连接失败";
                return false;
            }
            const char *socket_path = "/var/lib/mysql/mysql.sock";
            if (!mysql_real_connect(my, host.c_str(), ::user.c_str(), passwd.c_str(), db.c_str(), port, socket_path, 0)) {

                LOG(FATAL) << "连接数据库失败! 错误详情:\n"
                      << "主机: " << host << "\n"
                      << "用户: " << ::user << "\n"
                      << "数据库: " << db << "\n"
                      << "端口: " << port << "\n"
                      << "MySQL错误: " << mysql_error(my) << "\n"
                      << "系统错误: " << strerror(errno) << "\n";
                mysql_close(my); 
                return false;
            }
            LOG(INFO)<<"连接数据库成功!!!"<<"\n";

            mysql_autocommit(my, 1);
            if (mysql_set_character_set(my, "utf8") != 0) 
            {
                LOG(FATAL) << "设置字符集失败";
            }

            char escaped_username[256] = {0};
            mysql_real_escape_string(my, escaped_username, user.username.c_str(), user.username.size());
            
            std::string enc_pass = MD5(user.password);
            char escaped_password[256] = {0};
            mysql_real_escape_string(my, escaped_password, enc_pass.c_str(), enc_pass.size());

            time_t now = time(nullptr);
            char time_str[64] = {0};
            strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&now));

            std::string sql = "INSERT INTO oj_users (username, password, created_at) VALUES ('";
            sql += escaped_username;
            sql += "', '";
            sql += escaped_password;
            sql += "', '";
            sql += time_str;
            sql += "')";

            bool success = (mysql_query(my, sql.c_str()) == 0);
            if (!success) 
            {
                LOG(FATAL)<<"注册用户失败"<<"\n";
            } 
            else 
            {
                LOG(INFO)<<"注册用户成功""\n";
            }

            mysql_close(my);
            return success;
        }



        // 验证登录
        bool VerifyLogin(const std::string& username, const std::string& password) {
            MYSQL* my = mysql_init(nullptr);
            if (!my) 
            {
                LOG(FATAL) << "初始化数据库连接失败";
                return false;
            }
            const char *socket_path = "/var/lib/mysql/mysql.sock";
            if (!mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, socket_path, 0)) 
            {
                LOG(FATAL) << "连接数据库失败! 错误详情:\n"
                      << "主机: " << host << "\n"
                      << "用户: " << user << "\n"
                      << "数据库: " << db << "\n"
                      << "端口: " << port << "\n"
                      << "MySQL错误: " << mysql_error(my) << "\n"
                      << "系统错误: " << strerror(errno) << "\n";
                mysql_close(my); 
                return false;
            }
            LOG(INFO)<<"连接数据库成功!!!"<<"\n";
            
            mysql_autocommit(my, 1);
            if (mysql_set_character_set(my, "utf8") != 0) {
                LOG(FATAL) << "设置字符集失败";
            }

            char escaped_username[256] = {0};
            mysql_real_escape_string(my, escaped_username, username.c_str(), username.size());
            
            std::string enc_pass = MD5(password);
            char escaped_password[256] = {0};
            mysql_real_escape_string(my, escaped_password, enc_pass.c_str(), enc_pass.size());

            std::string sql = "SELECT username, password, created_at FROM oj_users WHERE username = '";
            sql += escaped_username;
            sql += "' AND password = '";
            sql += escaped_password;
            sql += "' LIMIT 1";

            bool success = false;
            if (mysql_query(my, sql.c_str()) == 0) 
            {
                MYSQL_RES* res = mysql_store_result(my);
                if (res && mysql_num_rows(res) == 1) 
                {
                    success = true;
                }
                if (res) 
                {
                    mysql_free_result(res); 
                }
            } 
            else 
            {
                LOG(FATAL)<<"登录查询失败"<<"\n";                       
            }

            mysql_close(my);
            return success;
        }

        bool QueryMySql(const std::string &sql,std::vector<Question>* out)
        {
            MYSQL* my = mysql_init(nullptr);
            if (!my) 
            {
                LOG(FATAL) << "初始化数据库连接失败";
                return false;
            }
            const char *socket_path = "/var/lib/mysql/mysql.sock";
            if (!mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, socket_path, 0)) 
            {
                LOG(FATAL) << "连接数据库失败! 错误详情:\n"
                      << "主机: " << host << "\n"
                      << "用户: " << user << "\n"
                      << "数据库: " << db << "\n"
                      << "端口: " << port << "\n"
                      << "MySQL错误: " << mysql_error(my) << "\n"
                      << "系统错误: " << strerror(errno) << "\n";
                mysql_close(my); 
                return false;
            }
            LOG(INFO)<<"连接数据库成功!!!"<<"\n";

            
            mysql_autocommit(my, 1);
            if (mysql_set_character_set(my, "utf8") != 0) {
                LOG(FATAL) << "设置字符集失败";
            }

            if(0!=mysql_query(my,sql.c_str()))
            {
                LOG(WARNING)<<"execute erro !!!"<<strerror(errno)<<" "<<mysql_error(my)<<"\n";
                mysql_close(my);
                return false;
            }

            MYSQL_RES *res=mysql_store_result(my);
            int rows=mysql_num_rows(res);
            int cols=mysql_num_fields(res);
            Question q;
            for(int i=0;i<rows;i++)
            {
                MYSQL_ROW row=mysql_fetch_row(res); // 获取一行数据
                q.number=row[1];
                q.title=row[2];
                q.star=row[3];
                q.desc=row[4];
                q.header=row[5];
                q.tail=row[6];
                q.cpu_limit=std::stoi(row[7]);
                q.mem_limit=std::stoi(row[8]);
                out->push_back(q);
            }

            if (res) 
            {
                mysql_free_result(res); // 【补充释放】
            }
            mysql_close(my);
            return true;
        }

        bool GetAllQuestions(std::vector<Question> *out)
        {
            std::string sql;
            sql+="select * from ";
            sql+=oj_questions;
            return QueryMySql(sql,out);
        }

        bool GetOneQuestion(const std::string& number,Question* q)
        {
            bool res=false;
            std::string sql;
            sql+="select * from ";
            sql+=oj_questions;
            sql+=" where number=";
            sql+=number;
            std::vector<Question> result;
            if(QueryMySql(sql,&result))
            {
                if(result.size()==1)
                {
                    *q=result[0];
                    res=true;
                }
            }
            return res;
        }
    };
}